package com.atguigu.gmall.activity.service.impl;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.activity.util.CacheHelper;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.MD5;
import com.atguigu.gmall.model.activity.OrderRecode;
import com.atguigu.gmall.model.activity.SeckillGoods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class SeckillGoodsServiceImpl implements SeckillGoodsService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;


    /**
     * 查询秒杀商品列表
     *
     * @return
     */
    @Override
    public List<SeckillGoods> findAll() {
        // 查询所有的value
        List<SeckillGoods> seckillGoodsList = redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).values();
        return seckillGoodsList;
    }

    /**
     * 根据秒杀商品Id查询秒杀商品的详情
     *
     * @param skuId
     * @return
     */
    @Override
    public SeckillGoods getSeckillGoods(Long skuId) {
        SeckillGoods seckillGoods = (SeckillGoods) redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).get(skuId.toString());
        return seckillGoods;
    }

    /**
     * 预下单
     *
     * @param userId
     * @param skuId
     */
    @Override
    public void seckillOrder(String userId, Long skuId) {
        /*
            1 校验状态位{高并发时，可能秒杀商品会被抢购空}
            2 检验是否下过单 setnx
            3 校验秒杀商品库存剩余{秒杀商品的数量是有 list 存储在redis中}
            4 创建临时订单对象 OrderRecode
            5 临时订单数据存入缓存
            6 更新数据库
         */

        // 校验状态位
        String state = (String) CacheHelper.get(skuId.toString());
        if ("0".equals(state)) {
            return;
        }

        // 校验用户是否下过单 {setnx 当且仅当key不存在时操作才成功}
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(RedisConst.SECKILL_USER + userId, skuId, RedisConst.SECKILL__TIMEOUT, TimeUnit.SECONDS);
        if (!flag) {// 说明用户已经下单
            return;
        }

        //校验秒杀商品库存剩余
        String goodsId = (String) redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId.toString()).rightPop();
        if (StringUtils.isEmpty(goodsId)) {// 为空说明售罄 告知其他节点状态位改为0

            // 使用redis的订阅广播通知其他节点更改状态位为0
            redisTemplate.convertAndSend("seckillpush", skuId + ":0");

            return;
        }

        // 创建临时订单对象 OrderRecode
        OrderRecode orderRecode = new OrderRecode();
        orderRecode.setUserId(userId);
        orderRecode.setSeckillGoods(getSeckillGoods(skuId));
        orderRecode.setNum(1);// 只允许抢购一件商品
        orderRecode.setOrderStr(MD5.encrypt(userId + skuId));// 订单号

        // 临时订单数据存入缓存
        redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).put(orderRecode.getUserId(), orderRecode);

        // 更新数据库秒杀商品的剩余库存
        updateStockCount(orderRecode.getSeckillGoods().getSkuId());

    }

    /**
     * 更新数据库秒杀商品的剩余库存
     *
     * @param skuId
     */
    private void updateStockCount(Long skuId) {

        // 先获取缓存中秒杀商品剩余的库存数
        Long stockCount = redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId.toString()).size();

        if (stockCount % 2 == 0) {// 满足更新一次数据库
            SeckillGoods seckillGoods = getSeckillGoods(skuId);
            // 更新数据库数据
            seckillGoods.setStockCount(stockCount.intValue());//设置剩余库存
            seckillGoodsMapper.updateById(seckillGoods);

            // 同时更新缓存中秒杀商品数据
            redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).put(seckillGoods.getSkuId().toString(), seckillGoods);
        }
    }

    /**
     * 根据商品id与用户ID查看订单信息
     *
     * @param skuId
     * @param userId
     * @return
     */
    @Override
    public Result checkOrder(Long skuId, String userId) {
        /*
         1 判断缓存中是否存在用户
         2 判断用户是否抢单成功{预下单} 获取抢购数据
         3 判断用户是否下过单{若真正下单 使用新的key将订单数据保存进缓存}
         4 判断状态位
         */

        // 1 判断缓存中是否存在用户
        Boolean isExistUser = redisTemplate.hasKey(RedisConst.SECKILL_USER + userId);

        if (isExistUser) {

            // 2 判断用户是否抢单成功{预下单} 获取预下单数据
            Boolean ishasKey = redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).hasKey(userId);
            if (ishasKey) {// 抢单成功
                // 获取预下单数据 OrderRecode
                OrderRecode orderRecode = (OrderRecode) redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).get(userId);
                // 返回状态码215 抢单成功
                return Result.build(orderRecode, ResultCodeEnum.SECKILL_SUCCESS);
            }
        }

        // 3 判断用户是否下过单{若下单 使用新的key将订单数据保存进缓存}
        Boolean isExitOrder = redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS_USERS).hasKey(userId);
        if (isExitOrder) {// 已经下单
            // 获取订单id
            String orderId = (String) redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS_USERS).get(userId);
            // 返回状态码218 下单成功
            return Result.build(orderId, ResultCodeEnum.SECKILL_ORDER_SUCCESS);
        }

        // 4 判断状态位{存储在Map中}
        String state = (String) CacheHelper.get(skuId.toString());
        if ("0".equals(state)) {
            return Result.build(null, ResultCodeEnum.SECKILL_FINISH);
        }
        // 其余情况处于排队中
        return Result.build(null, ResultCodeEnum.SECKILL_RUN);
    }
}
